package ipc;

import rddl.RDDL.TYPE_NAME;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import rddl.ActionGenerator;
import rddl.EvalException;
import rddl.RDDL;
import rddl.State;
import rddl.RDDL.DOMAIN;
import rddl.RDDL.INSTANCE;
import rddl.RDDL.LCONST;
import rddl.RDDL.NONFLUENTS;
import rddl.RDDL.OBJECTS_DEF;
import rddl.RDDL.PVAR_INST_DEF;
import rddl.RDDL.PVAR_NAME;
import rddl.competition.Client;
import rddl.parser.parser;
import rddl.policy.Policy;
import util.Pair;

//sort computers by outtdegree
//reboot first failed computer

public class SysAdminHeuristic {
	public DOMAIN _d;
	public NONFLUENTS _n;
	public INSTANCE _i;
	public State _state;
	public List<Pair<PVAR_NAME, ArrayList<LCONST>>> sortedList = new ArrayList<Pair<PVAR_NAME, ArrayList<LCONST>>>();
	private double avgR;
	private double varR;
	
	public SysAdminHeuristic(String domain, String instance) throws Exception {
		super();
		
		RDDL dom = parser.parse(new File(domain));
		_d = dom._tmDomainNodes.values().iterator().next();
		
		RDDL inst = parser.parse(new  File(instance));
		_i = inst._tmInstanceNodes.values().iterator().next();
		
		_n = inst._tmNonFluentNodes.values().iterator().next();
		
		makeSortedList();
		play();
		
		System.out.println(avgR + " " + varR);
	}

	private void play() {
		Policy policy = new Policy() {
		
			public double avg_reward = 0 ;
			public double variance = 0;//sum of squares till done
			public int horizon;
			public int numRounds = 30;
			private long ptime;
			
			
			@Override
			public void roundEnd(double reward) {
//				super.roundEnd(reward);
				avg_reward += reward;
				variance += (reward*reward);
			}
			
			@Override
			public void sessionEnd(double total_reward) {
//				super.sessionEnd(total_reward);
				avg_reward /= numRounds;
				variance -= numRounds*(avg_reward*avg_reward);
				variance /= (numRounds-1);
				variance = Math.sqrt(variance);
//				System.out.println("Average reqward : " + avg_reward);
//				System.out.println("Stdev: " + variance);
				avgR = avg_reward;
				varR = variance;
			}
			
			@Override
			public void roundInit(double time_left, int horizon, int round_number, int total_rounds) {
//				super.roundInit(time_left, horizon, round_number, total_rounds);
				this.horizon = horizon;
				this.ptime = System.currentTimeMillis();
			}
		
			@Override
			public ArrayList<PVAR_INST_DEF> getActions(State s) throws EvalException{
				
				TreeMap<String, ArrayList<PVAR_INST_DEF>> legals = ActionGenerator.getLegalBoolActionMap(s);
				
				boolean done = false;
				ArrayList<PVAR_INST_DEF> ret = new ArrayList<PVAR_INST_DEF>();
				
				for( Pair<PVAR_NAME, ArrayList<LCONST>> p : sortedList ){
					if( ret.size() == _i._nNonDefActions ){
						done = true;
						break;
					}
					
					Boolean val = (Boolean)s.getPVariableAssign(p._o1, p._o2);
					if( val == false ){
						ArrayList<PVAR_INST_DEF> oldret = new ArrayList<PVAR_INST_DEF>(ret);
						ret.add(new PVAR_INST_DEF("reboot", (Boolean)true, p._o2));
						try {
							s.checkStateActionConstraints(ret);
							
						} catch (EvalException e) {
							ret = oldret;
						}
					}
				}
				
				
				
				return ret;
				
			}
		};
		
		Client cl = new Client(this._d, this._i, this._n, policy, "localhost", 2316, "BEAVER!!!");
	}

	private void makeSortedList() {
		
		List<Pair<Integer, String>> sorteddegrees = new ArrayList<Pair<Integer,String>>();
//		List<Pair<Integer, String>> sortedindegrees = new ArrayList<Pair<Integer,String>>();
		
		Map<LCONST, Integer> outdegrees = new HashMap<LCONST, Integer>();
		Map<LCONST, Integer> indegrees = new HashMap<LCONST, Integer>();
		
		Map<String, LCONST> lconstmap = new HashMap<String, LCONST>();
		
		for( PVAR_INST_DEF nf : _n._alNonFluents ){
			if( nf._sPredName.toString().equals("CONNECTED") ){
				LCONST src = nf._alTerms.get(0);
				Integer curr = outdegrees.get(src);
				curr = ( curr == null ) ? 0 : curr;
				++curr;
				outdegrees.put(src, curr);
				
				LCONST dest = nf._alTerms.get(1);
				curr = indegrees.get(dest);
				curr = ( curr == null ) ? 0 : curr;
				++curr;
				indegrees.put(dest, curr);
				
//				System.out.println(src + "->" + dest);
			}
		}
		
		OBJECTS_DEF comps = _n._hmObjects.get(new TYPE_NAME("computer"));
		for( LCONST comp : comps._alObjects ){
			if( outdegrees.get(comp) == null ){
				outdegrees.put(comp, 0);
			}
			
			if(indegrees.get(comp) == null ){
				indegrees.put(comp, 0);
			}
		}
		
		
		for( LCONST lc : outdegrees.keySet() ){
			int diff = outdegrees.get(lc) - indegrees.get(lc);
			sorteddegrees.add(new Pair<Integer, String>(diff, lc.toString()));
			lconstmap.put(lc.toString(), lc);
		}
		
//		for( Map.Entry<LCONST, Integer> entry : outdegrees.entrySet() ){
//			sortedoutdegrees.add(new Pair<Integer, String>(entry.getValue(), entry.getKey().toString()));
//			lconstmap.put(entry.getKey().toString(),entry.getKey());
//		}
//		
//		for( Map.Entry<LCONST, Integer> entry : indegrees.entrySet() ){
//			sortedindegrees.add(new Pair<Integer, String>(entry.getValue(), entry.getKey().toString()));
//			lconstmap.put(entry.getKey().toString(),entry.getKey());
//		}
		
//		System.out.println(outdegrees);
		
//		Collections.sort(sortedoutdegrees);
//		Collections.reverse(sortedoutdegrees);
//		
//		Collections.sort(sortedindegrees);
//		
//		System.out.println(sortedoutdegrees);
//		System.out.println(sortedindegrees);
		
		Collections.sort(sorteddegrees);
		Collections.reverse(sorteddegrees);
		
//		System.out.println(sorteddegrees);
		
		for( Pair<Integer, String> p : sorteddegrees ){
			ArrayList<LCONST> thislist = new ArrayList<LCONST>();
			thislist.add(lconstmap.get(p._o2));
			sortedList.add(new Pair<PVAR_NAME, ArrayList<LCONST>>(new PVAR_NAME("running"), thislist));
		}
		
//		System.out.println(sortedList);
		
	}
	
	public static void main(String[] args) throws Exception {
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__1.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__2.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__3.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__4.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__5.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__6.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__7.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__8.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__9.rddl");
		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_inst_mdp__10.rddl");
		
//		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_star_11.rddl");
//		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_star_12.rddl");
//		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_star_13.rddl");
//		new SysAdminHeuristic("/scratch/final_comp/rddl/sysadmin_mdp.rddl", "/scratch/final_comp/rddl/sysadmin_star_14.rddl");
	}
}
